<?php if (! defined('BASEPATH')) exit('No direct access allowed.');

/**
 * My_Loader
 * 扩展核心组建 Loader组件
 *
 * Loader组件在CI里面是一个很重要的组件，功能比较明了，但是代码却不少。
 * 同 Controller组件 相比：Controller组件的代码也只有十来行，但它却可以做很多事
 * 一定程度上要归功于Loader组件这个好助手或者好基友。
 *
 * 相关阅读：
 * CodeIgniter源码分析之Loader.php
 * <http://blog.163.com/wu_guoqing/blog/static/196537018201281662319790>
 * <http://codeigniter.org.cn/forums/thread-15889-1-1.html>
 */

class My_Loader extends CI_Loader {

    /**
     * 已加载的服务类列表
     *
     * @var array
     * @access protected
     */
    protected $_ci_services = array();

    /**
     * 加载服务类的路径
     *
     * @var string
     * @access protected
     */
    protected $_ci_service_paths = array();

    public function __construct() {
        parent::__construct();
        $this->_ci_service_paths = array(APPPATH);
    }

    /**
     * 载入服务类
     * 用于业务逻辑的实现
     * 仿照CI_Loader的model加载的方法实现
     *
     * @param string    $service    要加载的服务类名称
     * @param string    $name       重命名服务类名称
     * @param bool      $db_conn    加载同时开启数据库连接
     * @return	void
     */
    public function service($service, $name = '', $db_conn = false) {
        //可以以数组形式同时加载多个$service
        if (is_array($service)) {
            foreach ($service as $babe) {
                $this->service($babe);
            }
            return;
        }
        if ($service == '') return;

        $path = '';

        // 有子目录，解析出的文件名和路径
        if (($last_slash = strrpos($service, '/')) !== false) {
            $path = substr($service, 0, $last_slash + 1);
            $service = substr($service, $last_slash + 1);
        }

        //如果没有给当前service定义名字，则以$service本身作为名字
        if ($name == '') $name = $service;

        //如果已经加载过此service，直接退出本函数
        if (in_array($name, $this->_ci_services, true)) return;

        $CI = &get_instance();
        //如果加载的service名字与之前加载过的类有冲突，则报错。
        if (isset($CI->$name)) {
            show_error('The service name you are loading is the name of a resource that is already being used: ' . $name);
        }
        //service文件必段是全小写
        $service = strtolower($service);

        foreach ($this->_ci_service_paths as $service_path) {
            //如果服务类文件不存在，则跳过
            if (! file_exists($service_path . 'services/' . $path . $service . '.php')) continue;

            if ($db_conn !== false and ! class_exists('CI_DB')) {
                if ($db_conn === true) $db_conn = '';
                $CI->load->database($db_conn, false, true);
            }

            //加载父类service
            if (! class_exists('MY_Service')) load_class('Service', 'core');

            //引入当前service
            require_once ($service_path . 'services/' . $path . $service . '.php');

            //把文件名的第一个字母大写作为类名，CI规定的命名规范。
            $service = ucfirst($service);

            $CI->$name = new $service();

            //保存在Loader::_ci_services中，以后可以用它来判断某个service是否已经加载过。
            $this->_ci_services[] = $name;
            return;
        }

        // 找不到服务类报错
        show_error('Unable to locate the service you have specified: ' . $service);
    }
}


/* End of file My_Loader.php */
/* Location: ./application/core/My_Loader.php */
